/**
 * OpenHarmony 工程结构分析器
 * 
 * 用于分析 OpenHarmony 工程的目录结构、BUILD.gn 依赖关系
 * 帮助准确定位源文件所属的 BUILD.gn 和对应的测试 BUILD.gn
 */

import * as vscode from 'vscode';
import * as path from 'path';
import * as fs from 'fs';
import { Logger } from '../../../src/logger/Logger';

/**
 * 工程配置信息（从 bundle.json 解析）
 */
export interface BundleConfig {
    name: string;
    component: {
        name: string;
        subsystem: string;
        deps?: {
            components?: string[];
        };
    };
}

/**
 * GNI 配置信息
 */
export interface GNIConfig {
    filePath: string;
    variables: Map<string, string>;  // 变量定义，如 user_file_service_path
    declares: Map<string, any>;      // declare_args() 定义的参数
}

/**
 * BUILD.gn 分析结果
 */
export interface BuildGNInfo {
    filePath: string;
    type: 'source' | 'test';  // 是源码 BUILD.gn 还是测试 BUILD.gn
    targets: BuildTarget[];
    imports: string[];  // import() 的 .gni 文件
    projectRoot?: string;  // 工程根目录
    relativeToProject?: string;  // 相对于工程根目录的路径
}

/**
 * GN Config 定义
 */
export interface ConfigDefinition {
    name: string;                // config 名称
    body: string;                // config 完整 body
    include_dirs: string[];      // 提取的 include_dirs
    defines: string[];           // 提取的 defines
    cflags: string[];            // 提取的 cflags
    cflags_cc: string[];         // 提取的 cflags_cc
}

/**
 * GN Template 定义
 */
export interface TemplateDefinition {
    name: string;                // template 名称
    body: string;                // template 完整 body
    sourcesTemplate: string[];   // 提取的 sources 模板
    filePath: string;            // template 定义所在文件
}

/**
 * Template 调用生成的虚拟目标
 */
export interface VirtualTarget {
    name: string;                // 目标名（可能包含表达式）
    type: string;                // 目标类型 (template_expansion)
    sources: string[];           // 解析后的 sources
    deps: string[];
    include_dirs: string[];
    external_deps: string[];
}

/**
 * BUILD.gn 中的目标（target）
 */
export interface BuildTarget {
    name: string;
    type: string;  // ohos_shared_library, ohos_unittest, etc.
    sources: string[];
    include_dirs: string[];
    deps: string[];
    external_deps: string[];
    configs?: string[];
    defines?: string[];
    sanitize?: any;
    branch_protector_ret?: string;
    isTemplateExpansion?: boolean;  // 标记是否为template展开生成的目标
}

/**
 * 源文件分析结果
 */
export interface SourceFileInfo {
    filePath: string;
    fileName: string;
    relativePath: string;  // 相对于工程根目录的路径
    projectRoot: string;   // 工程根目录（有 bundle.json 的目录）
    bundleConfig?: BundleConfig;
    gniConfigs: GNIConfig[];
    sourceBuildGN?: BuildGNInfo;  // 源文件所属的 BUILD.gn
    testBuildGN?: BuildGNInfo;    // 对应的测试 BUILD.gn
    testDirectory?: string;       // 测试目录（如 test/unittest）
}

export class ProjectAnalyzer {
    /**
     * 分析源文件的工程结构
     */
    public async analyzeSourceFile(filePath: string): Promise<SourceFileInfo> {
        Logger.info(`[ProjectAnalyzer] 开始分析源文件: ${filePath}`);

        const fileName = path.basename(filePath);
        const projectRoot = await this.findProjectRoot(filePath);
        
        if (!projectRoot) {
            throw new Error('无法找到工程根目录（bundle.json 所在目录）');
        }

        const relativePath = path.relative(projectRoot, filePath);
        Logger.info(`[ProjectAnalyzer] 工程根目录: ${projectRoot}`);
        Logger.info(`[ProjectAnalyzer] 相对路径: ${relativePath}`);

        // 读取 bundle.json
        const bundleConfig = await this.readBundleConfig(projectRoot);
        
        // 查找所有 .gni 文件
        const gniConfigs = await this.findAndParseGNIFiles(projectRoot);
        
        // 查找源文件所属的 BUILD.gn
        const sourceBuildGN = await this.findSourceBuildGN(filePath, projectRoot);
        
        // 查找对应的测试 BUILD.gn
        const testBuildGN = await this.findTestBuildGN(filePath, projectRoot, sourceBuildGN);
        
        // 确定测试目录
        const testDirectory = this.determineTestDirectory(projectRoot, filePath);

        return {
            filePath,
            fileName,
            relativePath,
            projectRoot,
            bundleConfig,
            gniConfigs,
            sourceBuildGN,
            testBuildGN,
            testDirectory
        };
    }

    /**
     * 查找工程根目录（bundle.json 所在目录）
     */
    private async findProjectRoot(filePath: string): Promise<string | null> {
        let currentDir = path.dirname(filePath);
        const maxDepth = 20;
        let depth = 0;

        while (depth < maxDepth) {
            const bundlePath = path.join(currentDir, 'bundle.json');
            if (fs.existsSync(bundlePath)) {
                Logger.info(`[ProjectAnalyzer] 找到 bundle.json: ${bundlePath}`);
                return currentDir;
            }

            const parentDir = path.dirname(currentDir);
            if (parentDir === currentDir) {
                break;  // 已到根目录
            }
            currentDir = parentDir;
            depth++;
        }

        Logger.warn(`[ProjectAnalyzer] 未找到 bundle.json`);
        return null;
    }

    /**
     * 读取 bundle.json 配置
     */
    private async readBundleConfig(projectRoot: string): Promise<BundleConfig | undefined> {
        const bundlePath = path.join(projectRoot, 'bundle.json');
        try {
            const content = fs.readFileSync(bundlePath, 'utf-8');
            const config = JSON.parse(content);
            Logger.info(`[ProjectAnalyzer] 读取 bundle.json: ${config.name}`);
            return config as BundleConfig;
        } catch (error) {
            Logger.error(`[ProjectAnalyzer] 读取 bundle.json 失败: ${error}`);
            return undefined;
        }
    }

    /**
     * 查找并解析所有 .gni 文件
     */
    private async findAndParseGNIFiles(projectRoot: string): Promise<GNIConfig[]> {
        const gniConfigs: GNIConfig[] = [];
        
        try {
            const files = this.findFilesRecursive(projectRoot, '.gni', 3);  // 最多搜索 3 层
            
            for (const file of files) {
                const config = await this.parseGNIFile(file);
                if (config) {
                    gniConfigs.push(config);
                }
            }
            
            Logger.info(`[ProjectAnalyzer] 找到 ${gniConfigs.length} 个 .gni 文件`);
        } catch (error) {
            Logger.error(`[ProjectAnalyzer] 查找 .gni 文件失败: ${error}`);
        }

        return gniConfigs;
    }

    /**
     * 递归查找文件
     */
    private findFilesRecursive(dir: string, extension: string, maxDepth: number, currentDepth: number = 0): string[] {
        if (currentDepth >= maxDepth) {
            return [];
        }

        const results: string[] = [];
        
        try {
            const entries = fs.readdirSync(dir, { withFileTypes: true });
            
            for (const entry of entries) {
                const fullPath = path.join(dir, entry.name);
                
                if (entry.isDirectory()) {
                    // 跳过 node_modules, .git 等目录
                    if (!['node_modules', '.git', 'out', 'dist'].includes(entry.name)) {
                        results.push(...this.findFilesRecursive(fullPath, extension, maxDepth, currentDepth + 1));
                    }
                } else if (entry.isFile() && entry.name.endsWith(extension)) {
                    results.push(fullPath);
                }
            }
        } catch (error) {
            // 忽略权限错误等
        }

        return results;
    }

    /**
     * 解析 .gni 文件
     */
    private async parseGNIFile(filePath: string): Promise<GNIConfig | null> {
        try {
            const content = fs.readFileSync(filePath, 'utf-8');
            const variables = new Map<string, string>();
            const declares = new Map<string, any>();

            // 解析变量定义，如：user_file_service_path = "//foundation/filemanagement/user_file_service"
            const varRegex = /^(\w+)\s*=\s*"([^"]+)"/gm;
            let match;
            while ((match = varRegex.exec(content)) !== null) {
                variables.set(match[1], match[2]);
            }

            // 解析 declare_args() 块
            const declareArgsRegex = /declare_args\(\)\s*\{([^}]+)\}/gs;
            const declareMatch = declareArgsRegex.exec(content);
            if (declareMatch) {
                const argsContent = declareMatch[1];
                const argRegex = /(\w+)\s*=\s*([^\n]+)/g;
                let argMatch;
                while ((argMatch = argRegex.exec(argsContent)) !== null) {
                    declares.set(argMatch[1].trim(), argMatch[2].trim());
                }
            }

            if (variables.size > 0 || declares.size > 0) {
                Logger.info(`[ProjectAnalyzer] 解析 .gni: ${path.basename(filePath)}, 变量: ${variables.size}, 参数: ${declares.size}`);
                return {
                    filePath,
                    variables,
                    declares
                };
            }
        } catch (error) {
            Logger.error(`[ProjectAnalyzer] 解析 .gni 文件失败: ${filePath}, ${error}`);
        }

        return null;
    }

    /**
     * 查找源文件所属的 BUILD.gn
     */
    private async findSourceBuildGN(filePath: string, projectRoot: string): Promise<BuildGNInfo | undefined> {
        Logger.info(`[ProjectAnalyzer] 🔍 ========== 开始查找源文件的 BUILD.gn ==========`);
        Logger.info(`[ProjectAnalyzer]   - 源文件: ${filePath}`);
        Logger.info(`[ProjectAnalyzer]   - 工程根: ${projectRoot}`);
        Logger.info(`[ProjectAnalyzer]   - 相对路径: ${path.relative(projectRoot, filePath)}`);

        // 策略 1: 向上查找（从源文件目录向上）
        Logger.info(`[ProjectAnalyzer] 📂 策略1: 向上查找...`);
        let currentDir = path.dirname(filePath);
        const maxDepth = 10;
        let depth = 0;

        while (depth < maxDepth && currentDir.startsWith(projectRoot)) {
            const buildGNPath = path.join(currentDir, 'BUILD.gn');
            Logger.info(`[ProjectAnalyzer]   [深度 ${depth}] 检查目录: ${currentDir}`);
            
            if (fs.existsSync(buildGNPath)) {
                Logger.info(`[ProjectAnalyzer]   📄 发现 BUILD.gn: ${buildGNPath}`);
                
                const buildGN = await this.parseBuildGN(buildGNPath, projectRoot);
                if (buildGN) {
                    Logger.info(`[ProjectAnalyzer]   📄 BUILD.gn 解析成功，共 ${buildGN.targets.length} 个目标`);
                    if (this.buildGNContainsFile(buildGN, filePath)) {
                        buildGN.type = 'source';
                        Logger.info(`[ProjectAnalyzer] ✅ 策略1成功！找到匹配的源码 BUILD.gn`);
                        return buildGN;
                    } else {
                        Logger.info(`[ProjectAnalyzer]   ❌ BUILD.gn 不包含该源文件`);
                    }
                } else {
                    Logger.warn(`[ProjectAnalyzer]   ⚠️ BUILD.gn 解析失败`);
                }
            } else {
                Logger.info(`[ProjectAnalyzer]   ⏭️  未发现 BUILD.gn`);
            }

            currentDir = path.dirname(currentDir);
            depth++;
        }

        // 策略 2: 广度搜索（在源文件的祖先目录中搜索所有子目录的 BUILD.gn）
        Logger.info(`[ProjectAnalyzer] 📁 策略2: 广度搜索（搜索兄弟目录和子目录）...`);
        
        // 从源文件所在目录开始，向上5层（增加搜索范围）
        let searchRoot = path.dirname(filePath);
        for (let level = 0; level < 5; level++) {
            if (!searchRoot.startsWith(projectRoot)) {
                break;
            }
            
            Logger.info(`[ProjectAnalyzer]   🔍 [层级 ${level}] 搜索根目录: ${searchRoot}`);
            Logger.info(`[ProjectAnalyzer]       相对工程根: ${path.relative(projectRoot, searchRoot)}`);
            
            const found = await this.searchBuildGNInDirectory(searchRoot, filePath, projectRoot, 3);
            if (found) {
                found.type = 'source';
                Logger.info(`[ProjectAnalyzer] ✅ 策略2成功！在第 ${level} 层找到匹配的源码 BUILD.gn`);
                Logger.info(`[ProjectAnalyzer]   BUILD.gn 路径: ${found.filePath}`);
                Logger.info(`[ProjectAnalyzer]   相对工程根: ${path.relative(projectRoot, found.filePath)}`);
                return found;
            }
            
            searchRoot = path.dirname(searchRoot);
        }

        Logger.error(`[ProjectAnalyzer] ❌ ========== 所有策略都失败，未找到包含该文件的源码 BUILD.gn ==========`);
        Logger.error(`[ProjectAnalyzer]   建议检查：`);
        Logger.error(`[ProjectAnalyzer]   1. BUILD.gn 文件是否存在`);
        Logger.error(`[ProjectAnalyzer]   2. BUILD.gn 中的 sources 是否包含该文件`);
        Logger.error(`[ProjectAnalyzer]   3. 路径格式是否正确（相对路径/绝对路径）`);
        return undefined;
    }

    /**
     * 在指定目录及其子目录中搜索包含源文件的 BUILD.gn
     */
    private async searchBuildGNInDirectory(
        searchDir: string,
        sourceFilePath: string,
        projectRoot: string,
        maxDepth: number,
        currentDepth: number = 0
    ): Promise<BuildGNInfo | undefined> {
        if (currentDepth > maxDepth) {
            Logger.info(`[ProjectAnalyzer]     ${'  '.repeat(currentDepth)}⏹️  达到最大深度 ${maxDepth}`);
            return undefined;
        }
        
        if (!searchDir.startsWith(projectRoot)) {
            Logger.info(`[ProjectAnalyzer]     ${'  '.repeat(currentDepth)}⏹️  超出工程根目录`);
            return undefined;
        }

        const indent = '  '.repeat(currentDepth + 2);
        Logger.info(`[ProjectAnalyzer]   ${indent}📂 [深度 ${currentDepth}] ${path.relative(projectRoot, searchDir) || '.'}`);

        try {
            const entries = fs.readdirSync(searchDir, { withFileTypes: true });
            
            // 先检查当前目录的 BUILD.gn
            const buildGNPath = path.join(searchDir, 'BUILD.gn');
            if (fs.existsSync(buildGNPath)) {
                Logger.info(`[ProjectAnalyzer]   ${indent}  📄 发现 BUILD.gn`);
                const buildGN = await this.parseBuildGN(buildGNPath, projectRoot);
                if (buildGN) {
                    Logger.info(`[ProjectAnalyzer]   ${indent}  📄 解析成功，共 ${buildGN.targets.length} 个目标`);
                    if (this.buildGNContainsFile(buildGN, sourceFilePath)) {
                        Logger.info(`[ProjectAnalyzer]   ${indent}  ✅ 匹配！`);
                        return buildGN;
                    } else {
                        Logger.info(`[ProjectAnalyzer]   ${indent}  ❌ 不匹配`);
                    }
                } else {
                    Logger.warn(`[ProjectAnalyzer]   ${indent}  ⚠️ 解析失败`);
                }
            }
            
            // 递归搜索子目录
            const subdirs = entries.filter(e => 
                e.isDirectory() && 
                !e.name.startsWith('.') && 
                e.name !== 'node_modules' &&
                e.name !== 'test' &&  // 跳过test目录
                e.name !== 'unittest' &&
                e.name !== 'fuzztest'
            );
            
            if (subdirs.length > 0) {
                Logger.info(`[ProjectAnalyzer]   ${indent}  🔍 搜索 ${subdirs.length} 个子目录...`);
            }
            
            for (const entry of subdirs) {
                const subDir = path.join(searchDir, entry.name);
                const found = await this.searchBuildGNInDirectory(
                    subDir,
                    sourceFilePath,
                    projectRoot,
                    maxDepth,
                    currentDepth + 1
                );
                if (found) {
                    return found;
                }
            }
        } catch (err) {
            Logger.warn(`[ProjectAnalyzer]   ${indent}  ⚠️ 读取目录失败: ${err}`);
        }

        return undefined;
    }

    /**
     * 解析 GNI 文件中的变量定义
     */
    private parseGNIVariables(gniPath: string, projectRoot: string): Map<string, string> {
        const variables = new Map<string, string>();
        
        try {
            if (!fs.existsSync(gniPath)) {
                return variables;
            }
            
            const content = fs.readFileSync(gniPath, 'utf-8');
            
            // 匹配变量定义: var_name = "value"
            const varRegex = /^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*"([^"]+)"\s*$/gm;
            let match;
            
            while ((match = varRegex.exec(content)) !== null) {
                variables.set(match[1], match[2]);
            }
            
            Logger.info(`[ProjectAnalyzer]   📝 从 ${path.basename(gniPath)} 解析了 ${variables.size} 个变量`);
        } catch (error) {
            Logger.warn(`[ProjectAnalyzer]   ⚠️ 解析 GNI 文件失败: ${error}`);
        }
        
        return variables;
    }

    /**
     * 递归替换GN变量
     */
    private resolveGNVariable(text: string, variables: Map<string, string>, maxDepth = 10): string {
        let result = text;
        let depth = 0;
        
        while (depth < maxDepth && result.includes('${')) {
            let changed = false;
            for (const [key, value] of variables.entries()) {
                const placeholder = '${' + key + '}';
                if (result.includes(placeholder)) {
                    result = result.replace(new RegExp('\\$\\{' + key + '\\}', 'g'), value);
                    changed = true;
                }
            }
            if (!changed) break;
            depth++;
        }
        
        return result;
    }

    /**
     * 将GN绝对路径转换为文件系统路径
     */
    private gnPathToFilePath(gnPath: string, projectRoot: string): string {
        if (gnPath.startsWith('//')) {
            // //foundation/... 需要找到对应的实际目录
            // 在 OHCode 环境中，//foundation/... 对应 OHCode/xxx
            const relativePath = gnPath.substring(2); // 去掉 //
            
            // 尝试多种路径组合
            const possiblePaths = [
                path.join(projectRoot, relativePath),
                path.join(projectRoot, '..', relativePath),
            ];
            
            for (const p of possiblePaths) {
                if (fs.existsSync(p)) {
                    return path.normalize(p);
                }
            }
            
            // 如果找不到，返回最可能的路径
            return path.join(projectRoot, relativePath);
        }
        return gnPath;
    }

    /**
     * 查找对应的测试 BUILD.gn
     */
    private async findTestBuildGN(filePath: string, projectRoot: string, sourceBuildGN?: BuildGNInfo): Promise<BuildGNInfo | undefined> {
        // 策略 1: 查找 test/unittest/BUILD.gn
        const testUnittestPath = path.join(projectRoot, 'test', 'unittest', 'BUILD.gn');
        if (fs.existsSync(testUnittestPath)) {
            Logger.info(`[ProjectAnalyzer] 找到测试 BUILD.gn: ${testUnittestPath}`);
            const buildGN = await this.parseBuildGN(testUnittestPath, projectRoot);
            if (buildGN) {
                buildGN.type = 'test';
                return buildGN;
            }
        }

        // 策略 2: 查找 test/BUILD.gn
        const testPath = path.join(projectRoot, 'test', 'BUILD.gn');
        if (fs.existsSync(testPath)) {
            Logger.info(`[ProjectAnalyzer] 找到测试 BUILD.gn: ${testPath}`);
            const buildGN = await this.parseBuildGN(testPath, projectRoot);
            if (buildGN) {
                buildGN.type = 'test';
                return buildGN;
            }
        }

        // 策略 3: 在源文件同级或上级目录查找 test 目录
        if (sourceBuildGN) {
            const sourceDir = path.dirname(sourceBuildGN.filePath);
            const testDir = path.join(sourceDir, '..', 'test', 'unittest');
            const testBuildGNPath = path.join(testDir, 'BUILD.gn');
            
            if (fs.existsSync(testBuildGNPath)) {
                Logger.info(`[ProjectAnalyzer] 找到测试 BUILD.gn (相对路径): ${testBuildGNPath}`);
                const buildGN = await this.parseBuildGN(testBuildGNPath, projectRoot);
                if (buildGN) {
                    buildGN.type = 'test';
                    return buildGN;
                }
            }
        }

        Logger.warn(`[ProjectAnalyzer] 未找到测试 BUILD.gn`);
        return undefined;
    }

    /**
     * 解析 BUILD.gn 文件
     */
    private async parseBuildGN(filePath: string, projectRoot: string): Promise<BuildGNInfo | null> {
        try {
            const content = fs.readFileSync(filePath, 'utf-8');
            const gnDir = path.dirname(filePath);
            
            // 解析 import() 语句
            const imports: string[] = [];
            const importRegex = /import\("([^"]+)"\)/g;
            let importMatch;
            while ((importMatch = importRegex.exec(content)) !== null) {
                imports.push(importMatch[1]);
            }

            // 解析 GNI 文件中的变量
            const variables = new Map<string, string>();
            for (const importPath of imports) {
                if (importPath.startsWith('//build/')) {
                    continue; // 跳过系统导入
                }
                
                // 解析相对路径
                const resolvedPath = path.resolve(gnDir, importPath);
                if (fs.existsSync(resolvedPath)) {
                    const gniVars = this.parseGNIVariables(resolvedPath, projectRoot);
                    for (const [key, value] of gniVars.entries()) {
                        variables.set(key, value);
                    }
                }
            }

            if (variables.size > 0) {
                Logger.info(`[ProjectAnalyzer]   📚 加载了 ${variables.size} 个 GNI 变量`);
            }

            // 提取 config 定义
            const configs = this.extractConfigDefinitions(content);
            if (configs.length > 0) {
                Logger.info(`[ProjectAnalyzer]   📦 发现 ${configs.length} 个 config 定义`);
            }

            // 提取 template 定义
            const templates = this.extractTemplateDefinitions(content);
            if (templates.length > 0) {
                Logger.info(`[ProjectAnalyzer]   📝 发现 ${templates.length} 个 template 定义`);
            }

            // 提取 template 调用生成的虚拟目标
            const virtualTargets = this.extractTemplateInvocations(content, templates, projectRoot, gnDir, variables);

            // 解析目标（targets）- 使用手动大括号匹配处理多层嵌套
            const targets: BuildTarget[] = [];
            const targetHeaderRegex = /(ohos_\w+|group|executable)\("([^"]+)"\)\s*\{/g;
            let targetHeaderMatch;
            
            while ((targetHeaderMatch = targetHeaderRegex.exec(content)) !== null) {
                const targetType = targetHeaderMatch[1];
                const targetName = targetHeaderMatch[2];
                const startPos = targetHeaderMatch.index + targetHeaderMatch[0].length - 1; // { 的位置
                
                // 手动匹配大括号，支持任意层级嵌套
                const targetBody = this.extractBlockContent(content, startPos);
                
                if (!targetBody) {
                    Logger.warn(`[ProjectAnalyzer]   ⚠️ 无法提取目标体: ${targetName}`);
                    continue;
                }

                Logger.info(`[ProjectAnalyzer]   🎯 解析目标: ${targetName} (${targetType})`);
                Logger.info(`[ProjectAnalyzer]      目标体长度: ${targetBody.length} 字符`);
                
                // 调试：显示目标体的前500个字符
                const bodyPreview = targetBody.substring(0, 500).replace(/\n/g, '\\n');
                Logger.info(`[ProjectAnalyzer]      目标体预览: ${bodyPreview}...`);

                const sources = this.extractArrayField(targetBody, 'sources');
                const include_dirs = this.extractArrayField(targetBody, 'include_dirs');
                const deps = this.extractArrayField(targetBody, 'deps');
                const external_deps = this.extractArrayField(targetBody, 'external_deps');
                
                // 解析 GN 变量 - sources
                const resolvedSources = sources.map(s => {
                    const resolved = this.resolveGNVariable(s, variables);
                    const fsPath = this.gnPathToFilePath(resolved, projectRoot);
                    // 相对路径需要相对于 BUILD.gn 所在目录
                    if (!path.isAbsolute(fsPath) && !fsPath.startsWith('//')) {
                        return path.resolve(gnDir, fsPath);
                    }
                    return fsPath;
                });
                
                Logger.info(`[ProjectAnalyzer]      ✅ 提取结果: sources=${sources.length} (resolved: ${resolvedSources.length}), include_dirs=${include_dirs.length}, deps=${deps.length}, external_deps=${external_deps.length}`);

                const target: BuildTarget = {
                    name: targetName,
                    type: targetType,
                    sources: resolvedSources,  // 使用解析后的路径
                    include_dirs,
                    deps,
                    external_deps,
                };

                targets.push(target);
            }

            // 将虚拟目标（template展开）添加到targets数组
            targets.push(...virtualTargets);

            Logger.info(`[ProjectAnalyzer] 解析 BUILD.gn: ${path.basename(filePath)}, 找到 ${targets.length} 个目标 (包含 ${virtualTargets.length} 个template展开)`);

            return {
                filePath,
                type: filePath.includes('/test/') ? 'test' : 'source',
                targets,
                imports,
                projectRoot,
                relativeToProject: path.relative(projectRoot, filePath)
            };
        } catch (error) {
            Logger.error(`[ProjectAnalyzer] 解析 BUILD.gn 失败: ${filePath}, ${error}`);
            return null;
        }
    }

    /**
     * 提取大括号块内容（支持任意层级嵌套）
     */
    private extractBlockContent(code: string, startBrace: number): string | null {
        let depth = 1;
        let i = startBrace + 1;
        
        while (i < code.length && depth > 0) {
            const char = code[i];
            
            // 处理字符串字面量，避免误判字符串中的大括号
            if (char === '"' || char === "'") {
                const quote = char;
                i++;
                while (i < code.length && code[i] !== quote) {
                    if (code[i] === '\\') i++; // 跳过转义字符
                    i++;
                }
            } else if (char === '{') {
                depth++;
            } else if (char === '}') {
                depth--;
            }
            i++;
        }
        
        if (depth === 0) {
            return code.substring(startBrace + 1, i - 1);
        }
        
        return null;
    }
    
    /**
     * 从 GN 内容中提取数组字段（增强版：支持 +=、多行、嵌套）
     */
    private extractArrayField(content: string, fieldName: string): string[] {
        const items: string[] = [];
        
        Logger.info(`[ProjectAnalyzer]         提取字段: ${fieldName}`);
        
        // 策略1: 匹配 fieldName = [ ... ]（支持多行和嵌套大括号）
        const assignRegex = new RegExp(`${fieldName}\\s*=\\s*\\[([^\\]]*(?:\\[[^\\]]*\\][^\\]]*)*)\\]`, 'gs');
        let match = assignRegex.exec(content);
        
        if (match) {
            Logger.info(`[ProjectAnalyzer]         ✓ 策略1匹配成功 (=)`);
            const arrayContent = match[1];
            const preview = arrayContent.substring(0, 200).replace(/\n/g, '\\n');
            Logger.info(`[ProjectAnalyzer]         数组内容预览: ${preview}...`);
            this.extractItemsFromArrayContent(arrayContent, items);
            Logger.info(`[ProjectAnalyzer]         提取到 ${items.length} 项`);
        } else {
            Logger.info(`[ProjectAnalyzer]         ✗ 策略1未匹配 (=)`);
        }
        
        // 策略2: 匹配 fieldName += [ ... ]（支持多次追加）
        const appendRegex = new RegExp(`${fieldName}\\s*\\+=\\s*\\[([^\\]]*(?:\\[[^\\]]*\\][^\\]]*)*)\\]`, 'gs');
        let appendCount = 0;
        while ((match = appendRegex.exec(content)) !== null) {
            appendCount++;
            Logger.info(`[ProjectAnalyzer]         ✓ 策略2匹配成功 (+=) 第${appendCount}次`);
            const arrayContent = match[1];
            this.extractItemsFromArrayContent(arrayContent, items);
        }
        if (appendCount === 0) {
            Logger.info(`[ProjectAnalyzer]         ✗ 策略2未匹配 (+=)`);
        }
        
        // 策略3: 匹配 filter_include(xxx, [ ... ])
        const filterIncludeRegex = new RegExp(`${fieldName}\\s*=\\s*filter_include\\([^,]+,\\s*\\[([^\\]]+)\\]\\)`, 'gs');
        match = filterIncludeRegex.exec(content);
        
        if (match) {
            Logger.info(`[ProjectAnalyzer]         ✓ 策略3匹配成功 (filter_include)`);
            const arrayContent = match[1];
            this.extractItemsFromArrayContent(arrayContent, items);
        } else {
            Logger.info(`[ProjectAnalyzer]         ✗ 策略3未匹配 (filter_include)`);
        }
        
        // 策略4: 提取条件编译块中的 sources（支持 if/else）
        const conditionalItems = this.extractConditionalArrays(content, fieldName);
        if (conditionalItems.length > 0) {
            Logger.info(`[ProjectAnalyzer]         ✓ 策略4: 从条件编译中提取 ${conditionalItems.length} 项`);
            for (const item of conditionalItems) {
                if (!items.includes(item)) {
                    items.push(item);
                }
            }
        }
        
        Logger.info(`[ProjectAnalyzer]         📝 ${fieldName} 最终提取: ${items.length} 项`);
        
        return items;
    }
    
    /**
     * 从数组内容中提取所有项
     */
    private extractItemsFromArrayContent(content: string, items: string[]): void {
        // 匹配双引号或单引号包裹的字符串
        const itemRegex = /"([^"]+)"|'([^']+)'/g;
        let itemMatch;
        
        while ((itemMatch = itemRegex.exec(content)) !== null) {
            const item = itemMatch[1] || itemMatch[2];
            if (item && !items.includes(item)) {  // 去重
                items.push(item);
            }
        }
    }
    
    /**
     * 提取条件编译块中的数组项
     * 支持 if (...) { fieldName += [...] } 和 else { ... } 块
     */
    private extractConditionalArrays(content: string, fieldName: string): string[] {
        const items: string[] = [];
        
        // 匹配 if (...) { ... } 或 if (...) { ... } else { ... }
        // 使用手动大括号匹配来处理嵌套
        const ifRegex = /\bif\s*\([^)]+\)\s*\{/g;
        let match;
        
        while ((match = ifRegex.exec(content)) !== null) {
            const startPos = match.index + match[0].length - 1; // { 的位置
            const ifBlock = this.extractBlockContent(content, startPos);
            
            if (ifBlock) {
                // 在 if 块中递归查找 fieldName
                const ifItems = this.extractArrayFieldRecursive(ifBlock, fieldName);
                items.push(...ifItems);
                
                // 查找对应的 else 或 else if 块
                const endPos = startPos + ifBlock.length + 1;
                const remainingContent = content.substring(endPos);
                const elseMatch = remainingContent.match(/^\s*else\s*\{/);
                
                if (elseMatch) {
                    const elseStartPos = elseMatch[0].length - 1;
                    const elseBlock = this.extractBlockContent(remainingContent, elseStartPos);
                    if (elseBlock) {
                        const elseItems = this.extractArrayFieldRecursive(elseBlock, fieldName);
                        items.push(...elseItems);
                    }
                }
            }
        }
        
        return items;
    }
    
    /**
     * 递归提取数组字段（简化版，用于条件块）
     */
    private extractArrayFieldRecursive(content: string, fieldName: string): string[] {
        const items: string[] = [];
        
        // 匹配 fieldName = [ ... ] 或 fieldName += [ ... ]
        const regex = new RegExp(`${fieldName}\\s*[+]?=\\s*\\[([^\\]]*(?:\\[[^\\]]*\\][^\\]]*)*)\\]`, 'gs');
        let match;
        
        while ((match = regex.exec(content)) !== null) {
            this.extractItemsFromArrayContent(match[1], items);
        }
        
        // 递归处理嵌套的 if 块
        const nestedItems = this.extractConditionalArrays(content, fieldName);
        items.push(...nestedItems);
        
        return items;
    }

    /**
     * 提取 config 定义
     */
    private extractConfigDefinitions(gnContent: string): ConfigDefinition[] {
        const configs: ConfigDefinition[] = [];
        const regex = /config\s*\(\s*"([^"]+)"\s*\)\s*\{/g;
        
        let match;
        while ((match = regex.exec(gnContent)) !== null) {
            const configName = match[1];
            const startPos = match.index + match[0].length - 1; // { 的位置
            const body = this.extractBlockContent(gnContent, startPos);
            
            if (body) {
                Logger.info(`[ProjectAnalyzer]   ⚙️ 发现 config: ${configName}`);
                
                const include_dirs = this.extractArrayField(body, 'include_dirs');
                const defines = this.extractArrayField(body, 'defines');
                const cflags = this.extractArrayField(body, 'cflags');
                const cflags_cc = this.extractArrayField(body, 'cflags_cc');
                
                Logger.info(`[ProjectAnalyzer]      include_dirs: ${include_dirs.length}, defines: ${defines.length}`);
                
                configs.push({
                    name: configName,
                    body: body,
                    include_dirs: include_dirs,
                    defines: defines,
                    cflags: cflags,
                    cflags_cc: cflags_cc
                });
            }
        }
        
        return configs;
    }

    /**
     * 提取 template 定义
     */
    private extractTemplateDefinitions(gnContent: string): TemplateDefinition[] {
        const templates: TemplateDefinition[] = [];
        const regex = /template\s*\(\s*"([^"]+)"\s*\)\s*\{/g;
        
        let match;
        while ((match = regex.exec(gnContent)) !== null) {
            const templateName = match[1];
            const startPos = match.index + match[0].length - 1; // { 的位置
            const body = this.extractBlockContent(gnContent, startPos);
            
            if (body) {
                Logger.info(`[ProjectAnalyzer]   📝 发现 template: ${templateName}`);
                
                const sourcesTemplate = this.extractArrayField(body, 'sources');
                Logger.info(`[ProjectAnalyzer]      sources 数量: ${sourcesTemplate.length}`);
                
                templates.push({
                    name: templateName,
                    body: body,
                    sourcesTemplate: sourcesTemplate,
                    filePath: ''
                });
            }
        }
        
        return templates;
    }

    /**
     * 提取 template 调用生成的虚拟目标
     */
    private extractTemplateInvocations(
        gnContent: string, 
        templates: TemplateDefinition[], 
        projectRoot: string, 
        gnDir: string,
        variables: Map<string, string>
    ): BuildTarget[] {
        const virtualTargets: BuildTarget[] = [];
        
        if (templates.length === 0) {
            return virtualTargets;
        }
        
        Logger.info(`[ProjectAnalyzer]   🔄 开始提取 template 调用...`);
        
        // 查找 foreach 循环
        const foreachRegex = /foreach\s*\(\s*(\w+)\s*,\s*(\w+)\s*\)\s*\{/g;
        let foreachMatch;
        
        while ((foreachMatch = foreachRegex.exec(gnContent)) !== null) {
            const loopVar = foreachMatch[1];  // e.g., "item"
            const arrayVar = foreachMatch[2]; // e.g., "ace_platforms"
            const foreachStartPos = foreachMatch.index + foreachMatch[0].length - 1;
            const foreachBody = this.extractBlockContent(gnContent, foreachStartPos);
            
            if (!foreachBody) continue;
            
            Logger.info(`[ProjectAnalyzer]   🔄 发现 foreach(${loopVar}, ${arrayVar})`);
            
            // 在 foreach body 中查找 template 调用
            for (const template of templates) {
                // 匹配 template_name("target_name") 或 template_name("target_" + expr)
                const invocationRegex = new RegExp(`${template.name}\\s*\\(\\s*"([^"]*)"[^)]*\\)`, 'g');
                let invMatch;
                
                while ((invMatch = invocationRegex.exec(foreachBody)) !== null) {
                    const targetNameExpr = invMatch[1]; // 可能包含动态拼接部分
                    
                    Logger.info(`[ProjectAnalyzer]      🎯 发现 template 调用: ${template.name}("${targetNameExpr}")`);
                    
                    // 创建虚拟目标
                    // 注意：targetNameExpr 可能包含 "name_" 这样的前缀，后面跟的 + item.name 会在正则中被截断
                    // 为了完整匹配，我们需要提取完整的调用表达式
                    const fullCallMatch = foreachBody.substring(invMatch.index).match(/^[^(]+\("([^"]+)"\s*(\+\s*[^)]+)?\)/);
                    
                    let finalTargetName = targetNameExpr;
                    if (fullCallMatch && fullCallMatch[2]) {
                        // 存在字符串拼接，如 "name_" + item.name
                        // 我们使用通配符模式: targetNameExpr 作为前缀
                        finalTargetName = `${targetNameExpr}*`;
                        Logger.info(`[ProjectAnalyzer]         检测到动态拼接，使用通配符: ${finalTargetName}`);
                    }
                    
                    // 解析 template body 中的 sources 路径
                    const resolvedSources = template.sourcesTemplate.map(s => {
                        const resolved = this.resolveGNVariable(s, variables);
                        const fsPath = this.gnPathToFilePath(resolved, projectRoot);
                        if (!path.isAbsolute(fsPath) && !fsPath.startsWith('//')) {
                            return path.resolve(gnDir, fsPath);
                        }
                        return fsPath;
                    });
                    
                    const virtualTarget: BuildTarget = {
                        name: finalTargetName,
                        type: 'template_expansion',
                        sources: resolvedSources,
                        deps: [],
                        include_dirs: [],
                        external_deps: [],
                        isTemplateExpansion: true
                    };
                    
                    virtualTargets.push(virtualTarget);
                    Logger.info(`[ProjectAnalyzer]         ✅ 创建虚拟目标: ${finalTargetName} (${resolvedSources.length} sources)`);
                }
            }
        }
        
        Logger.info(`[ProjectAnalyzer]   📊 总计创建 ${virtualTargets.length} 个虚拟目标`);
        return virtualTargets;
    }

    /**
     * 检查 BUILD.gn 是否包含指定文件
     */
    private buildGNContainsFile(buildGN: BuildGNInfo, filePath: string): boolean {
        const fileName = path.basename(filePath);
        const buildGNDir = path.dirname(buildGN.filePath);
        const normalizedFilePath = path.normalize(filePath);

        Logger.info(`[ProjectAnalyzer]       ┌─ 检查 BUILD.gn 是否包含文件 ────────────────`);
        Logger.info(`[ProjectAnalyzer]       │ 目标文件: ${normalizedFilePath}`);
        Logger.info(`[ProjectAnalyzer]       │ 文件名: ${fileName}`);
        Logger.info(`[ProjectAnalyzer]       │ BUILD.gn: ${buildGN.filePath}`);
        Logger.info(`[ProjectAnalyzer]       │ BUILD.gn目录: ${buildGNDir}`);
        Logger.info(`[ProjectAnalyzer]       └────────────────────────────────────────────`);

        if (!buildGN.targets || buildGN.targets.length === 0) {
            Logger.warn(`[ProjectAnalyzer]       ⚠️ BUILD.gn 没有任何目标定义`);
            return false;
        }

        for (const target of buildGN.targets) {
            Logger.info(`[ProjectAnalyzer]       🎯 目标: ${target.name} (${target.type})`);
            Logger.info(`[ProjectAnalyzer]          sources 数量: ${target.sources.length}`);
            
            if (target.sources.length === 0) {
                Logger.info(`[ProjectAnalyzer]          ⏭️  跳过（无 sources）`);
                continue;
            }

            // 显示前5个sources以供参考
            const previewSources = target.sources.slice(0, 5);
            Logger.info(`[ProjectAnalyzer]          示例 sources (前${previewSources.length}个):`);
            previewSources.forEach((s, idx) => {
                Logger.info(`[ProjectAnalyzer]            [${idx}] ${s}`);
            });
            if (target.sources.length > 5) {
                Logger.info(`[ProjectAnalyzer]            ... 还有 ${target.sources.length - 5} 个`);
            }
            
            for (let i = 0; i < target.sources.length; i++) {
                const source = target.sources[i];
                
                // sources 现在已经是 parseBuildGN 解析后的完整文件系统路径
                Logger.info(`[ProjectAnalyzer]          [${i}] 检查路径: "${source}"`);
                
                try {
                    // 标准化路径进行比较
                    const normalizedSource = path.normalize(source).toLowerCase().replace(/\\/g, '/');
                    const normalizedTarget = normalizedFilePath.toLowerCase().replace(/\\/g, '/');
                    
                    Logger.info(`[ProjectAnalyzer]              比较: "${normalizedSource}" === "${normalizedTarget}"`);
                    
                    // 完全匹配
                    if (normalizedSource === normalizedTarget) {
                        Logger.info(`[ProjectAnalyzer]          ✅✅✅ 找到完全匹配！`);
                        return true;
                    }
                    
                    // 后备：比较文件名和路径尾部（最后3级目录）
                    const sourceBaseName = path.basename(source);
                    if (sourceBaseName === fileName) {
                        const targetPathParts = normalizedTarget.split('/');
                        const sourcePathParts = normalizedSource.split('/');
                        
                        // 比较最后3个路径段
                        const depth = Math.min(3, targetPathParts.length, sourcePathParts.length);
                        let match = true;
                        for (let j = 1; j <= depth; j++) {
                            const targetPart = targetPathParts[targetPathParts.length - j];
                            const sourcePart = sourcePathParts[sourcePathParts.length - j];
                            if (targetPart !== sourcePart) {
                                match = false;
                                break;
                            }
                        }
                        
                        if (match) {
                            Logger.info(`[ProjectAnalyzer]          ✅✅ 找到文件名和路径尾部匹配（深度${depth}）！`);
                            return true;
                        } else {
                            Logger.info(`[ProjectAnalyzer]          ⚠️ 文件名匹配但路径不同`);
                        }
                    }
                    
                    Logger.info(`[ProjectAnalyzer]          ❌ 不匹配`);
                    
                } catch (e) {
                    Logger.warn(`[ProjectAnalyzer]          [${i}] ⚠️ 路径比较失败: ${e}`);
                    continue;
                }
            }
        }

        Logger.warn(`[ProjectAnalyzer]       ❌❌❌ 所有目标都不匹配`);
        return false;
    }

    /**
     * 确定测试目录
     */
    private determineTestDirectory(projectRoot: string, filePath: string): string {
        // 默认使用 test/unittest
        const testUnittestDir = path.join(projectRoot, 'test', 'unittest');
        if (fs.existsSync(testUnittestDir)) {
            return testUnittestDir;
        }

        // 如果不存在，使用 test
        const testDir = path.join(projectRoot, 'test');
        return testDir;
    }

    /**
     * 生成测试文件的信息摘要（用于前端显示）
     */
    public generateSourceFileSummary(info: SourceFileInfo): string {
        const lines: string[] = [];
        
        lines.push('📁 **工程信息**');
        lines.push(`- 工程名称: ${info.bundleConfig?.name || '未知'}`);
        lines.push(`- 子系统: ${info.bundleConfig?.component.subsystem || '未知'}`);
        lines.push(`- 工程根目录: \`${path.basename(info.projectRoot)}\``);
        lines.push('');

        lines.push('📄 **源文件信息**');
        lines.push(`- 文件名: \`${info.fileName}\``);
        lines.push(`- 相对路径: \`${info.relativePath}\``);
        lines.push('');

        if (info.sourceBuildGN) {
            lines.push('🔧 **源码 BUILD.gn**');
            lines.push(`- 路径: \`${info.sourceBuildGN.relativeToProject}\``);
            lines.push(`- 目标数量: ${info.sourceBuildGN.targets.length}`);
            if (info.sourceBuildGN.targets.length > 0) {
                const target = info.sourceBuildGN.targets[0];
                lines.push(`- 主要目标: \`${target.name}\` (${target.type})`);
            }
            lines.push('');
        }

        if (info.testBuildGN) {
            lines.push('🧪 **测试 BUILD.gn**');
            lines.push(`- 路径: \`${info.testBuildGN.relativeToProject}\``);
            lines.push(`- 测试目标数量: ${info.testBuildGN.targets.length}`);
            lines.push('');
        }

        if (info.gniConfigs.length > 0) {
            lines.push('⚙️ **GNI 配置**');
            for (const gni of info.gniConfigs) {
                const fileName = path.basename(gni.filePath);
                lines.push(`- \`${fileName}\`: ${gni.variables.size} 个变量`);
            }
        }

        return lines.join('\n');
    }
}

